/*
 * @Description:代码优化，开始把游戏分成了“第一次游戏”和“重新开始游戏”，有大量代码重复。优化：把第一次游戏合并到重新开始游戏中
 * @Author: bcygsws@163.com
 * @Date: 2020-11-06 23:50:39
 * @LastEditTime: 2020-11-09 00:34:50
 * @FilePath: \12-TODOSe:\Web-project\process25-typescript\code\ts7_game\index.ts
 */
/*
优化思路
1.把“重新开始游戏”点击按钮的事件处理函数，变为声明式StartGame
2.把steps userPlayer的初始值省略掉，值省略了，要添加相应的类型注解了
3.移除掉之前初始化操作时，给单元格绑定的事件-代码111-125行


*/
/**
 * 单击单元格
 * 1.获取到所有单元格列表
 * 2.遍历单元格列表
 * 3.为每个单元格添加点击事件
 */
// 是一个伪数组，伪数组也有按索引访问和length属性
var cells = document.querySelectorAll('.cell');
// 获取bord对象
var bord = document.querySelector('#bord');
// 判赢数组
var winArr = [
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8],
    [0, 3, 6],
    [1, 4, 7],
    [2, 5, 8],
    [0, 4, 8],
    [2, 4, 6]
];
// 优化1-变量存储角色，实现代码2
// let action = 'x';
// 优化2-枚举变量存储角色
var Player;
(function (Player) {
    Player["X"] = "x";
    Player["O"] = "o";
})(Player || (Player = {}));
//  判赢信息显示面板
var userPlayer;
// 声明变量steps,记录已经下棋的次数
var steps;
var message = document.querySelector('#message');
var btn = document.querySelector('#restart');
var p = document.querySelector('#winner');
// 将点击添加x的事件处理函数抽离
function handleClick(event) {
    console.log(event);
    //  event.target本质上是一个cell,且有类型注解
    var target = event.target;
    //  html模板中初始化时，#bord中放置的是x类，规定了先放x后放o
    // 实现方式1；
    // if (bord.classList.contains('x')) {
    // 	target.classList.add('x');
    // 	// x内容真实地填充到方格后，移除#bord的x类，置换成o类。下次放置提醒的是灰色的o
    // 	bord.classList.remove('x');
    // 	bord.classList.add('o');
    // } else {
    // 	target.classList.add('o');
    // 	bord.classList.remove('o');
    // 	bord.classList.add('x');
    // }
    // 优化1-变量存储角色，实现代码2
    // target.classList.add(action);
    // bord.classList.remove(action);
    // // 切换角色 思路：根据当前玩家，切换到另一个玩家的
    // action = action === 'x' ? 'o' : 'x';
    // bord.classList.add(action);
    // 优化2-枚举变量存储角色
    target.classList.add(userPlayer);
    // 下了一次棋，steps加1
    steps++;
    // 测试代码
    console.log(steps);
    // 判赢函数的调用
    var isWin = checkWin(userPlayer);
    // 先判断输赢，再判断平局
    if (isWin) {
        // console.log(userPlayer + '获胜了');
        // 获胜了'游戏获胜信息面板'展示，同时面板上显示“哪一方获胜的消息”
        message.style.display = 'block';
        p.innerText = userPlayer + '获胜了！';
        return;
    }
    /*
         “重新开始” 功能中，cell.addEventListener('click',handleClick,{once:true}) {once:true}不能少。
        否则点一个X,再点一次X就变成了O,并一直保持O,直到游戏结束。原因是：cell.addEventListener('click',handleClick)
        覆盖了上面的cell点击函数，原因是cell="x o",{once:true}使得添加x类后，再次点击该区域无效(点击事件被移除了)，就不会
        出现同一个cell中有x和o两个类样式的情况。有两个同样功能的类样式，根据css的三大特性(层叠、继承、优先级)，后面层叠前面的
    */
    if (steps === 9) {
        // console.log('这是个平局');
        message.style.display = 'block';
        p.innerText = '平局！';
        return;
    }
    // 特别注意：必须放在判赢函数后面，因为判赢函数中需要传入当前的userPlayer的值
    bord.classList.remove(userPlayer);
    // 切换角色 思路：判断当前玩家是x吗？是x就切换到o。是o就切换到x
    // 易错点：userPlayer赋值只可能是Play.A或者Play.B。不能代换写成'x'或者'o',即使打印结果是'x'或'o'
    userPlayer = userPlayer === Player.X ? Player.O : Player.X;
    // 此处的userPlayer值已经改变，为下一次下棋添加不同的提示做好准备
    bord.classList.add(userPlayer);
}
// 遍历cells列表
// cells.forEach(item => {
// 	let ele = item as HTMLDivElement;
// 	ele.addEventListener(
// 		'click',
// 		// function (event) {
// 		// 	console.log(event);
// 		// 	//  event.target本质上是一个cell,且有类型注解
// 		// 	let target = event.target as HTMLDivElement;
// 		// 	target.classList.add('x');
// 		// },
// 		handleClick,
// 		// 已经放置内容的x格子内，再次点击不应该再放x内容了，可以使用{once:true}来限制事件触发多次
// 		{ once: true }
// 	);
// });
/**
 * x放置完成了开始交替放置O了
 *技巧：在vscode界面鼠标指针放在'菜单栏'中，然后一直向左侧拖动，可以将
 *vscod界面和浏览器界面放置在同一个屏幕中
 *
 */
/**
 * 封装判赢函数
 *
 */
// 判赢函数封装
function checkWin(player) {
    return winArr.some(function (item) {
        // 1.先拿到每种获胜情况的三个索引,然后根据索引拿到对应的对象，使用对象的api,来判定是否含当前类名
        var index1 = item[0];
        var index2 = item[1];
        var index3 = item[2];
        // 2.拿到某种获胜其情况下的三个cell对象
        // let cell1 = cells[index1];
        // let cell2 = cells[index2];
        // let cell3 = cells[index3];
        // 3.判断三个对象中是否同时包含当前类样式(Player.X或者Player.O)
        /**
         * 重复的代码
         * 封装一个hasClass函数 hasClass(cell,player: Player)
         */
        if (hasClass(cells[index1], player) && hasClass(cells[index2], player) && hasClass(cells[index3], player)) {
            // 4.当某一时刻，获胜索引所在cell同时包含了一样的类样式，当前角色就获胜了
            return true; // 然后停止循环了
        }
        return false;
    });
}
/**
 * “重新开始”按钮点击事件-重置数据
 * a.隐藏获胜数据
 * b.清空棋盘
 * c.移除单元格点击事件（主要是针对游戏结束，还没被点击的方格，这里针对所有方格，结果是一样的）
 * d.重置下棋次数
 * e.bord重置为x
 * f.当前角色重置为x
 *
 */
btn.addEventListener('click', startGame);
function startGame() {
    // 1. 隐藏判赢信息面板
    message.style.display = 'none';
    // 4.重置下棋次数
    steps = 0;
    // 5.bord重置为x
    bord.classList.remove(userPlayer);
    // 6.当前角色为x
    userPlayer = Player.X;
    bord.classList.add(userPlayer);
    // 2.移除cells已经添加的'x'或者'o'类
    cells.forEach(function (item) {
        var cell = item;
        // 2.清空棋盘
        cell.classList.remove(Player.X, Player.O);
        // 3.移除点击事件
        cell.removeEventListener('click', handleClick);
        // 添加点击事件
        cell.addEventListener('click', handleClick, { once: true });
    });
}
// 初始化调用一次
startGame();
/**
 * hasClass函数的封装
 *
 */
function hasClass(cell, player) {
    return cell.classList.contains(player);
}
